package com.example.shiroredisdemo.config;


import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.ServletContainerSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.LinkedHashMap;

/**
 * @author ：Anitaxiaofeng
 * @description：
 * @create 2018-01-06
 **/
@Configuration
@Slf4j
public class ShiroConfig {

//    @Value("${spring.redis.host}")
//    private String host;
//
//    @Value("${spring.redis.port}")
//    private int port;

    @Bean
    public MyRedisProperties shiroProperties(){
        return new MyRedisProperties();
    }


    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager")SecurityManager manager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(manager);
        bean.setLoginUrl("/login");
        bean.setSuccessUrl("/index");
        bean.setUnauthorizedUrl("/unauthorized");
        LinkedHashMap<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/index","authc");
        filterChainDefinitionMap.put("/login","anon");
        filterChainDefinitionMap.put("/loginUser","anon");
        filterChainDefinitionMap.put("/add","roles[admin]");
        filterChainDefinitionMap.put("/edit","perms[edit]");
        filterChainDefinitionMap.put("/druid/**","anon");
        filterChainDefinitionMap.put("/**","user");

        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return bean;
    }

    @Bean("securityManager")
    public SecurityManager securityManager(@Qualifier("myRealm")MyRealm myRealm){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(myRealm);
//        manager.setCacheManager(cacheManager());
//        manager.setSessionManager(SessionManager());

        //session管理器
       manager.setSessionManager(sessionManager());
        //缓存管理器
        manager.setCacheManager(redisCacheManager());
        return manager;
    }

    @Bean("myRealm")
    public MyRealm myRealm(@Qualifier("credentialMatcher")CredentialMatcher credentialMatcher){
        MyRealm myRealm = new MyRealm();
//        myRealm.setCacheManager(new MemoryConstrainedCacheManager()); //缓存于内存中也可以
        myRealm.setCredentialsMatcher(credentialMatcher);
        return myRealm;
    }

    @Bean("credentialMatcher")
    public CredentialMatcher credentialMatcher(){
        return new CredentialMatcher();
    }

    @Bean(name ="sessionManager")
    public ServletContainerSessionManager sessionManager(){
        ServletContainerSessionManager sessionManager = new ServletContainerSessionManager();
        return sessionManager;
    }

    @Bean(name = "shiroRedisCacheManager")
    @DependsOn(value = "shiroRedisTemplate")
    public ShiroRedisCacheManager redisCacheManager(){
        ShiroRedisCacheManager cacheManager = new ShiroRedisCacheManager(shiroRedisTemplate());
        cacheManager.createCache("shiro_redis:");
        return cacheManager;
    }

    @Bean(name = "shiroRedisTemplate")
    public RedisTemplate<byte[],byte[]> shiroRedisTemplate(){
        RedisTemplate<byte[],byte[]> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory());
        return template;
    }

    @Primary
    @Bean(name = "connectFactory")
    @DependsOn(value = "shiroProperties")
    public RedisConnectionFactory connectionFactory(){
        JedisConnectionFactory conn = new JedisConnectionFactory();
        conn.setDatabase(shiroProperties().getDatabase());
        conn.setHostName(shiroProperties().getHost());
        conn.setPassword(shiroProperties().getPassword());
        conn.setPort(shiroProperties().getPort());
        conn.setTimeout(shiroProperties().getTimeout());
        log.info("1.初始化Redis缓存服务器(登陆用户Session管理及Shiro缓存管理).....");
        return conn;
    }


//    public RedisCacheManager cacheManager(){
//        RedisCacheManager redisCacheManager = new RedisCacheManager();
//        redisCacheManager.setRedisManager(redisManager());
//        return redisCacheManager;
//    }

//    public RedisManager redisManager(){
//        RedisManager redisManager = new RedisManager();
//        redisManager.setHost(host);
//        redisManager.setPort(port);
//        redisManager.setExpire(1800);
//        return redisManager;
//    }
//    public DefaultWebSessionManager SessionManager(){
//        DefaultWebSessionManager sessionManager  = new DefaultWebSessionManager();
//        sessionManager.setSessionDAO(redisSessionDAO());
//        return sessionManager;
//    }
//
//    public RedisSessionDAO redisSessionDAO(){
//        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
//        redisSessionDAO.setRedisManager(redisManager());
//        return redisSessionDAO;
//    }


    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }
}
